<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch, watchEffect } from 'vue'
import {
  ElButton,
  ElColorPicker,
  ElForm,
  ElFormItem,
  ElInput,
  ElPopover,
  ElText,
  ElDatePicker,
  ElTooltip,
  ElSelect,
  ElOption
} from 'element-plus'

const props = defineProps({
  linesData: {
    type: Array,
    default: () => [
      {
        id: '1',
        name: '线1'
      },
      {
        id: '2',
        name: '线2'
      },
      {
        id: '3',
        name: '线3'
      }
    ]
  } as unknown as any[],
  plansData: {
    type: Array,
    default: () => [
      {
        id: Math.random(),
        lineId: '1',
        name: '计划1',
        projectId: '1',
        projectName: '项目1',
        startTime: Date.now(),
        endTime: Date.now() + 1000 * 60 * 60 * 5,
        projectDeadline: Date.now() + 1000 * 60 * 60 * 1000
      },
      {
        id: Math.random(),
        lineId: '1',
        name: '计划',
        projectId: '2',
        projectName: '项目2',
        startTime: Date.now() + 1000 * 60 * 60 * 5,
        endTime: Date.now() + 1000 * 60 * 60 * 20,
        projectDeadline: Date.now() + 1000 * 60 * 60 * 20
      },
      {
        id: Math.random(),
        lineId: '2',
        name: '计划2',
        projectId: '1',
        projectName: '项目1',
        startTime: Date.now(),
        endTime: Date.now() + 1000 * 60 * 60 * 1000,
        projectDeadline: Date.now() + 1000 * 60 * 60 * 1000
      }
    ]
  } as unknown as any[],
  viewBoxWidth: {
    type: Number,
    default: 1000
  },
  limitStep: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['createPlan', 'editPlan', 'deletePlan', 'slicePlan'])

const viewBoxX = ref(0)
const lineHeight = ref(30)
const lineHeightPx = computed(() => `${lineHeight.value}px`)
const projects: any = ref([])
const legendPopoverVisible = ref(false)
const colors = [
  'hsl(0 80% 70%)',
  'hsl(50 80% 70%)',
  'hsl(100 80% 70%)',
  'hsl(150 80% 70%)',
  'hsl(200 80% 70%)',
  'hsl(250 80% 70%)',
  'hsl(300 80% 70%)',
  'hsl(350 80% 70%)'
]
let colorIndex = 0
// 生成项目对象
watch(
  () => props.plansData,
  () => {
    colorIndex = 0
    projects.value = []
    props.plansData.forEach((item) => {
      if (!projects.value.some((p) => p.id == item.projectId)) {
        projects.value.push({
          id: item.projectId,
          name: item.projectName,
          deadline: item.projectDeadline,
          color: colors[colorIndex]
        })

        colorIndex = (colorIndex + 1) % colors.length
      }
    })
  },
  { immediate: true }
)

class LineNode {
  isLineNode = true
  id = ''
  name = ''
  children = []
  rawData = {} // 原数据

  constructor(opt) {
    ;({ id: this.id, name: this.name } = opt)

    this.rawData = opt
  }

  add(timeNode) {
    if (timeNode.parent) timeNode.parent.remove(timeNode)

    timeNode.parent = this
    timeNode.lineId = this.id
    this.children.push(timeNode)
  }

  remove(timeNode) {
    const index = this.children.indexOf(timeNode)
    if (index !== -1) this.children.splice(index, 1)
  }
}

class TimeNode {
  isTimeNode = true
  id: string | number = ''
  name = ''
  parent = null
  startTime = 0
  endTime = 0
  rawData = {} as Record<string, any> // 原数据

  constructor(opt) {
    ;({ id: this.id, name: this.name, startTime: this.startTime, endTime: this.endTime } = opt)

    this.rawData = opt
  }
}

class PlanNode extends TimeNode {
  isPlanNode = true
  lineId = ''
  projectId = ''
  projectName = ''
  projectDeadline = null

  constructor(opt) {
    super(opt)
    ;({
      lineId: this.lineId,
      projectId: this.projectId,
      projectName: this.projectName,
      projectDeadline: this.projectDeadline
    } = opt)
  }

  slice(time) {
    const rawData = {
      id: Math.random(),
      lineId: this.lineId,
      name: this.name + '复制',
      projectId: this.projectId,
      projectName: this.projectName,
      startTime: time,
      endTime: this.endTime,
      projectDeadline: this.projectDeadline
    }

    this.endTime = time

    const newPlanNode = new PlanNode(rawData)

    this.parent.add(newPlanNode)

    return newPlanNode
  }
}

const today = new Date().setHours(0, 0, 0, 0)
const widthPerDay = ref(200) // 一天的像素宽度
const millisecondsPerDay = 1000 * 60 * 60 * 24 // 一天的毫秒
// 时间转像素x坐标
const time2X = (time: number) => {
  const x = ((time - today) / millisecondsPerDay) * widthPerDay.value

  return x
}
// 像素x坐标转时间
const x2Time = (x) => {
  const time = (+x / widthPerDay.value) * millisecondsPerDay + today

  return time
}
// 限制时间固定步长
const step = 1000 * 60 * 60 // 小时
const limitStepTime = (time) => {
  if (!props.limitStep) return time

  return Math.round(time / step) * step
}
// 编辑菜单的时间选择器，分秒限制函数
const timePickerDisabledFn = () => (props.limitStep ? new Array(60).fill(0).map((v, i) => i) : [])
// 时间刻度
const timeSacleLine = () => {
  const lineNodes: any = []
  const leftTime = x2Time(Math.floor(viewBoxX.value / widthPerDay.value) * widthPerDay.value)
  const rightTime = x2Time(viewBoxX.value + props.viewBoxWidth)
  const days = Math.ceil((rightTime - leftTime) / millisecondsPerDay)

  lineNodes[0] = new LineNode({ id: Math.random(), name: '年月' })
  lineNodes[1] = new LineNode({ id: Math.random(), name: '天' })
  lineNodes[2] = new LineNode({ id: Math.random(), name: '时' })

  let preStartTimeObj = new Date(0)
  let startTimeObj = new Date(leftTime)

  for (let i = 1; i <= days; i++) {
    const endTimeObj = new Date(leftTime + i * millisecondsPerDay)
    const date = startTimeObj.getDate()

    lineNodes[2].add(
      new TimeNode({
        id: Math.random(),
        name: '',
        startTime: startTimeObj.getTime(),
        endTime: endTimeObj.getTime()
      })
    )

    lineNodes[1].add(
      new TimeNode({
        id: Math.random(),
        name: date,
        startTime: startTimeObj.getTime(),
        endTime: endTimeObj.getTime()
      })
    )

    const preMonth = preStartTimeObj.getMonth()
    const year = startTimeObj.getFullYear()
    const month = startTimeObj.getMonth()

    if (lineNodes[0].children.length === 0 || preMonth !== month) {
      lineNodes[0].add(
        new TimeNode({
          id: Math.random(),
          name: `${year}-${month + 1}`,
          startTime: startTimeObj.getTime(),
          endTime: endTimeObj.getTime()
        })
      )
    } else {
      lineNodes[0].children.at(-1).endTime = endTimeObj.getTime()
    }

    preStartTimeObj = startTimeObj
    startTimeObj = endTimeObj
  }

  return lineNodes
}
// 日期线
const dateLines = computed(() => {
  return timeSacleLine()
})
// 计划线
const planLines = ref([])
// 计算属性修改不能渲染
watchEffect(() => {
  const linesNode = props.linesData.map((line) => {
    const lineNode = new LineNode(line)
    props.plansData
      .filter((item) => item.lineId === line.id)
      .map((item) => new PlanNode(item))
      .forEach((plan) => lineNode.add(plan))

    return lineNode
  })

  planLines.value = linesNode
})
// 拖动视图
const onSvgPointerDown = (e) => {
  const offsetX = viewBoxX.value
  const startX = e.x

  const onMousemove = (e) => {
    viewBoxX.value = offsetX - (e.x - startX)
  }

  const onMouseup = () => {
    document.removeEventListener('mousemove', onMousemove)
    document.removeEventListener('mouseup', onMouseup)
  }

  document.addEventListener('mousemove', onMousemove)
  document.addEventListener('mouseup', onMouseup)
}
// 参考线
const auxiliaryLine = reactive({
  time: 0,
  title: '',
  visible: false,
  slice: false
})

const onSvgPointerMove = (e) => {
  const { offsetX } = e
  const x = offsetX + viewBoxX.value
  const time = limitStepTime(x2Time(x))
  auxiliaryLine.time = time
  auxiliaryLine.title = new Date(time).toLocaleString()
}
// 缩放视图时间x转换率
const onSvgWheel = (e: WheelEvent) => {
  const sign = Math.sign(e.deltaY)
  let rate = 1

  if (sign == 1) rate = 2 / 3
  else if (sign == -1) rate = 3 / 2

  const offset = time2X(auxiliaryLine.time) - viewBoxX.value

  widthPerDay.value *= rate

  viewBoxX.value = time2X(auxiliaryLine.time) - offset
}
// 拖动节点
const targetNode = ref() // 需要编辑属性不能用shallowRef
const movePlan = ref(false)
// 上下拖动
const onLinePointerEnter = (lineNode) => {
  if (!movePlan.value) return

  lineNode.add(targetNode.value)
}

const onPlanPointerDown = (e, planNode) => {
  if (e.button !== 0) return
  // 切片
  if (auxiliaryLine.slice) return slicePlanNode(planNode)

  const { startTime, endTime } = planNode
  const startXTime = x2Time(e.x)

  targetNode.value = planNode
  // 左右拖动
  const onMousemove = (e) => {
    // down事件会触发move，判断一下
    if (e.movementX == 0 && e.movementY == 0) return

    const movementXTime = x2Time(e.x) - startXTime
    if (Math.abs(movementXTime) < step / 3) return

    movePlan.value = true

    planNode.startTime = limitStepTime(startTime + movementXTime)
    planNode.endTime = limitStepTime(endTime + movementXTime)
  }

  const onMouseup = () => {
    if (movePlan.value) emit('editPlan', planNode)

    targetNode.value = null
    movePlan.value = false
    menu.visible = false

    document.removeEventListener('mousemove', onMousemove)
    document.removeEventListener('mouseup', onMouseup)
  }

  document.addEventListener('mousemove', onMousemove)
  document.addEventListener('mouseup', onMouseup)
}
// 拖拽宽度
const onResizePointerDown = (e, planNode) => {
  const { endTime } = planNode
  const startXTime = limitStepTime(x2Time(e.x))

  const onMousemove = (e) => {
    const movementXTime = x2Time(e.x) - startXTime

    planNode.endTime = limitStepTime(endTime + movementXTime)
  }

  const onMouseup = () => {
    emit('editPlan', planNode)

    document.removeEventListener('mousemove', onMousemove)
    document.removeEventListener('mouseup', onMouseup)
  }

  document.addEventListener('mousemove', onMousemove)
  document.addEventListener('mouseup', onMouseup)
}
// 菜单
const menu = reactive({
  visible: false,
  x: 0,
  y: 0
})
const menuRef = ref()
/*
  svg及内部得鼠标事件的offsetX，offsetY是相对于svg的父元素
*/
const onContextmenu = (e, planNode) => {
  menu.visible = true
  ;({ offsetX: menu.x, offsetY: menu.y } = e)
  targetNode.value = planNode

  const onMouseDown = (e) => {
    if (
      !(
        menuRef.value === e.target ||
        menuRef.value?.compareDocumentPosition(e.target) & Node.DOCUMENT_POSITION_CONTAINED_BY
      )
    ) {
      targetNode.value = null
      menu.visible = false

      document.removeEventListener('mousedown', onMouseDown)
    }
  }

  document.addEventListener('mousedown', onMouseDown)
}
// 切片菜单
const sliceMenu = () => {
  auxiliaryLine.slice = true
  menu.visible = false
}
// 切片
const slicePlanNode = (planNode) => {
  const newPlan = planNode.slice(auxiliaryLine.time)
  auxiliaryLine.slice = false

  emit('slicePlan', [planNode, newPlan])
}
// 删除计划
const deletePlan = () => {
  if (!targetNode.value) return

  targetNode.value.parent?.remove(targetNode.value)
  emit('deletePlan', targetNode.value)

  menu.visible = false

  clear()
}

const createPlanVisible = ref(false)
// 打开新增框
const toggleCreateProject = () => {
  createPlanVisible.value = !createPlanVisible.value

  const newPlan = new PlanNode({
    id: Math.random(),
    name: '新计划',
    startTime: Date.now(),
    endTime: Date.now() + millisecondsPerDay,
    lineId: null,
    projectId: Math.random(),
    projectName: '新项目',
    projectDeadline: Date.now() + millisecondsPerDay
  })

  targetNode.value = newPlan
}
// 添加新项目计划
const createProject = () => {
  if (!targetNode.value.lineId) return

  planLines.value.find((l) => l.id == targetNode.value.lineId)?.add(targetNode.value)

  projects.value.push({
    id: targetNode.value.projectId,
    name: targetNode.value.projectName,
    deadline: targetNode.value.projectDeadline,
    color: colors[colorIndex]
  })

  colorIndex = (colorIndex + 1) % colors.length

  createPlanVisible.value = false
  emit('createPlan', targetNode.value)
}

const clear = () => {
  legendPopoverVisible.value = false
  createPlanVisible.value = false
  targetNode.value = null
  movePlan.value = false
  auxiliaryLine.slice = false
}

onMounted(() => {
  // 点击页面 清空选择
  document.addEventListener('pointerdown', clear)
})
</script>

<template>
  <div class="syt-gantt-chart">
    <div class="names-box">
      <div
        class="names-top"
        :style="{ height: `${lineHeight * dateLines.length}px` }"
        @pointerdown.stop=""
      >
        <ElPopover
          :visible="legendPopoverVisible"
          :teleported="false"
          width="unset"
          placement="right-start"
        >
          <template #reference>
            <ElButton
              type="primary"
              size="small"
              @click="legendPopoverVisible = !legendPopoverVisible"
            >
              项目图例
            </ElButton>
          </template>
          <ElForm>
            <ElFormItem v-for="project of projects" :key="project.id" :label="project.name">
              <ElColorPicker
                v-model="project.color"
                size="small"
                :teleported="false"
              ></ElColorPicker>
            </ElFormItem>
          </ElForm>
        </ElPopover>
        <ElPopover
          :visible="createPlanVisible"
          :teleported="false"
          width="260px"
          placement="right-start"
        >
          <template #reference>
            <ElButton
              style="margin: 10px 0"
              type="primary"
              size="small"
              @pointerdown="toggleCreateProject"
            >
              新增项目
            </ElButton>
          </template>
          <ElForm v-if="createPlanVisible && targetNode" label-width="80px">
            <ElFormItem label="项目名">
              <ElInput v-model="targetNode.projectName" size="small"></ElInput>
            </ElFormItem>
            <ElFormItem label="线">
              <ElSelect v-model="targetNode.lineId" :teleported="false">
                <ElOption
                  v-for="line of planLines"
                  :key="line.id"
                  :label="line.name"
                  :value="line.id"
                ></ElOption>
              </ElSelect>
            </ElFormItem>
            <ElFormItem label="计划名">
              <ElInput v-model="targetNode.name" size="small"></ElInput>
            </ElFormItem>
            <ElFormItem label="开始时间">
              <ElDatePicker
                v-model="targetNode.startTime"
                type="datetime"
                size="small"
                :clearable="false"
                value-format="x"
                :disabled-minutes="timePickerDisabledFn"
                :disabled-seconds="timePickerDisabledFn"
                :teleported="false"
              ></ElDatePicker>
            </ElFormItem>
            <ElFormItem label="结束时间">
              <ElDatePicker
                :model-value="targetNode.endTime"
                type="datetime"
                size="small"
                :clearable="false"
                value-format="x"
                :disabled-minutes="timePickerDisabledFn"
                :disabled-seconds="timePickerDisabledFn"
                :teleported="false"
                @update:model-value="(v) => (targetNode.endTime = targetNode.projectDeadline = v)"
              ></ElDatePicker>
            </ElFormItem>
            <ElFormItem>
              <ElButton
                style="margin: 10px 0"
                type="warning"
                size="small"
                @pointerdown="createProject"
              >
                确定
              </ElButton>
            </ElFormItem>
          </ElForm>
        </ElPopover>
      </div>
      <div v-for="line of linesData" :key="line.id" class="item-name">
        <ElTooltip :content="line.name">
          <ElText type="info" truncated>{{ line.name }}</ElText>
        </ElTooltip>
      </div>
    </div>
    <div class="chart-box">
      <svg
        :style="{ display: 'block' }"
        :width="viewBoxWidth"
        :height="`${lineHeight * (dateLines.length + planLines.length)}px`"
        :viewBox="`${viewBoxX} 0 ${viewBoxWidth} ${lineHeight * (dateLines.length + planLines.length)}`"
        xmlns="http://www.w3.org/2000/svg"
        @pointerdown="onSvgPointerDown"
        @pointermove="onSvgPointerMove"
        @wheel="onSvgWheel"
        @pointerenter="auxiliaryLine.visible = true"
        @pointerleave="auxiliaryLine.visible = false"
      >
        <defs>
          <filter id="shadow">
            <feDropShadow dx="1" dy="1" stdDeviation="0.5" flood-color="#036" flood-opacity="0.3" />
          </filter>
        </defs>
        <!-- 日期节点 -->
        <g
          v-for="(line, index) of dateLines"
          :key="line.id"
          :transform="`translate(0 ${lineHeight * index})`"
        >
          <line
            :x1="viewBoxX"
            :y1="lineHeight"
            :x2="viewBoxX + viewBoxWidth"
            :y2="lineHeight"
            stroke="#adf"
          />
          <g
            v-for="time of line.children"
            :key="time.id"
            :transform="`translate(${time2X(time.startTime)} 0)`"
          >
            <g v-if="line.name == '年月' || widthPerDay > 12">
              <title>{{ time.name }}</title>
              <rect
                :class="{ 'project-node': time.isPlanNode }"
                x="0"
                y="0"
                :width="Math.abs(time2X(time.endTime) - time2X(time.startTime))"
                :height="lineHeight"
                fill="#fafdff"
                stroke="rgb(0 0 0 / 0.05)"
              />
              <text
                :x="Math.abs(time2X(time.endTime) - time2X(time.startTime)) / 2"
                :y="lineHeight / 2"
                text-anchor="middle"
                dominant-baseline="middle"
                :font-size="12"
                fill="#9ab"
                style="user-select: none"
              >
                {{ time.name }}
              </text>
            </g>
            <g v-if="line.name == '时' && widthPerDay > 20">
              <line
                v-for="num in 24"
                :key="num"
                :x1="(Math.abs(time2X(time.endTime) - time2X(time.startTime)) / 24) * num"
                y1="0"
                :x2="(Math.abs(time2X(time.endTime) - time2X(time.startTime)) / 24) * num"
                :y2="num % 10 === 0 ? lineHeight / 2 : lineHeight / 3"
                :stroke="num % 10 === 0 ? '#ccc' : '#ddd'"
              ></line>
            </g>
          </g>
        </g>
        <!-- 项目计划线 -->
        <g
          v-for="(line, index) of planLines"
          :key="line.id"
          class="project-node"
          :transform="`translate(0 ${lineHeight * (index + dateLines.length)})`"
          @pointerenter="onLinePointerEnter(line)"
        >
          <line :x1="viewBoxX" y1="0" :x2="viewBoxX + viewBoxWidth" y2="0" stroke="#eee" />
          <!-- rect撑开line的g元素，不然pointerenter范围不够 -->
          <rect :x="viewBoxX" y="0" :width="viewBoxWidth" :height="lineHeight" fill="transparent" />
          <!-- 项目计划节点 -->
          <g
            v-for="planNode of line.children"
            :key="planNode.id"
            :transform="`translate(${time2X(planNode.startTime)} 0)`"
            @pointerdown.stop="onPlanPointerDown($event, planNode)"
            @contextmenu.stop.prevent="onContextmenu($event, planNode)"
          >
            <title>{{ planNode.projectName }} {{ planNode.name }}</title>
            <rect
              x="0"
              :y="lineHeight * 0.1"
              rx="8"
              :width="Math.abs(time2X(planNode.endTime) - time2X(planNode.startTime))"
              :height="lineHeight * 0.8"
              :fill="projects.find((item) => item.id === planNode.projectId)?.color"
              stroke="rgb(0 0 0 / 0.05)"
              opacity="0.6"
            />
            <text
              x="5"
              :y="lineHeight / 2"
              text-anchor="start"
              dominant-baseline="middle"
              :font-size="13"
              fill="#fff"
              filter="url(#shadow)"
              stroke="rgb(0 0 0 / 0.1)"
              paint-order="stroke"
              style="user-select: none"
              draggable="false"
            >
              {{ planNode.projectName }} {{ planNode.name }}
            </text>
            <line
              :x1="Math.abs(time2X(planNode.endTime) - time2X(planNode.startTime))"
              y1="0"
              :x2="Math.abs(time2X(planNode.endTime) - time2X(planNode.startTime))"
              :y2="lineHeight"
              stroke="transparent"
              stroke-width="5"
              style="cursor: ew-resize"
              @pointerdown.stop="onResizePointerDown($event, planNode)"
            ></line>
          </g>
        </g>
        <!-- 截止时间线 -->
        <g
          v-for="project of projects"
          :key="project.id"
          :transform="`translate(${time2X(project.deadline)}, 0)`"
        >
          <line
            x1="0"
            y1="0"
            :x2="0"
            :y2="`${lineHeight * (dateLines.length + planLines.length)}`"
            :stroke="project.color"
          ></line>
          <rect x="0" y="0" width="120" height="30" :fill="project.color" />
          <text
            x="5"
            :y="lineHeight / 2"
            text-anchor="start"
            dominant-baseline="middle"
            :font-size="12"
            fill="#059"
            style="user-select: none"
            draggable="false"
          >
            {{ new Date(project.deadline).toLocaleString() }}
          </text>
          <title>
            {{ project.name }}截止时间：{{ new Date(project.deadline).toLocaleString() }}
          </title>
        </g>
        <!-- 辅助线 -->
        <g
          v-if="auxiliaryLine.visible"
          :transform="`translate(${time2X(auxiliaryLine.time)}, 0)`"
          style="pointer-events: none"
        >
          <line
            x1="0"
            y1="0"
            :x2="0"
            :y2="`${lineHeight * (dateLines.length + planLines.length)}`"
            :stroke="auxiliaryLine.slice ? '#fda' : '#adf'"
            stroke-dasharray="5,5"
          ></line>
          <rect x="0" y="0" width="120" height="30" :fill="auxiliaryLine.slice ? '#fda' : '#adf'" />
          <text
            x="5"
            :y="lineHeight / 2"
            text-anchor="start"
            dominant-baseline="middle"
            :font-size="12"
            fill="#059"
            style="user-select: none"
            draggable="false"
          >
            {{ auxiliaryLine.title }}
          </text>
        </g>
      </svg>

      <menu
        v-if="menu.visible"
        ref="menuRef"
        :style="{ left: `${menu.x}px`, top: `${menu.y}px` }"
        class="contextmenu"
        @pointerdown.stop=""
      >
        <li class="menu-item" @pointerdown="sliceMenu">切片</li>
        <li class="menu-item">
          <ElPopover trigger="click" :teleported="false" width="260px">
            <template #reference>
              <div>编辑</div>
            </template>
            <ElForm v-if="targetNode" label-width="80px">
              <ElFormItem label="项目名">
                <ElInput v-model="targetNode.projectName" disabled size="small"></ElInput>
              </ElFormItem>
              <ElFormItem label="线">
                <ElSelect
                  v-model="targetNode.lineId"
                  :teleported="false"
                  @change="(v) => planLines.find((l) => l.id == v)?.add(targetNode)"
                >
                  <ElOption
                    v-for="line of planLines"
                    :key="line.id"
                    :label="line.name"
                    :value="line.id"
                  ></ElOption>
                </ElSelect>
              </ElFormItem>
              <ElFormItem label="计划名">
                <ElInput v-model="targetNode.name" size="small"></ElInput>
              </ElFormItem>
              <ElFormItem label="开始时间">
                <ElDatePicker
                  v-model="targetNode.startTime"
                  type="datetime"
                  size="small"
                  :clearable="false"
                  value-format="x"
                  :disabled-minutes="timePickerDisabledFn"
                  :disabled-seconds="timePickerDisabledFn"
                  :teleported="false"
                ></ElDatePicker>
              </ElFormItem>
              <ElFormItem label="结束时间">
                <ElDatePicker
                  v-model="targetNode.endTime"
                  type="datetime"
                  size="small"
                  :clearable="false"
                  value-format="x"
                  :teleported="false"
                  :disabled-minutes="timePickerDisabledFn"
                  :disabled-seconds="timePickerDisabledFn"
                ></ElDatePicker>
              </ElFormItem>
              <ElFormItem>
                <ElButton
                  style="margin: 10px 0"
                  type="warning"
                  size="small"
                  @pointerdown="
                    () => {
                      menu.visible = false
                      emit('editPlan', targetNode)
                    }
                  "
                >
                  确定
                </ElButton>
              </ElFormItem>
            </ElForm>
          </ElPopover>
        </li>
        <li class="menu-item" @pointerdown="deletePlan">删除</li>
      </menu>
    </div>
  </div>
</template>

<style scoped>
.syt-gantt-chart {
  --project-height: v-bind(lineHeightPx);
  color: #333;
  display: flex;
  overflow: auto;
}

.names-box {
  flex-shrink: 0;
  box-sizing: border-box;
  width: 120px;
  border-right: 1px solid #eee;
  background-color: #fff;
}

.names-top {
  box-sizing: border-box;
  padding: 10px;
}

.item-name {
  box-sizing: border-box;
  height: var(--project-height);
  padding: 5px 10px;
  border-top: 1px solid #eee;
}

.chart-box {
  position: relative;
  cursor: pointer;
  background-color: #fff;
}

.project-node {
  cursor: pointer;
}

.project-node:hover {
  filter: brightness(1.1);
}

.contextmenu {
  position: absolute;
  z-index: 1000;
  font-size: 13px;
  color: #333;
  box-sizing: border-box;
  width: 70px;
  padding: 0;
  border-radius: 5px;
  background-color: #fff;
  list-style: none;
  box-shadow: 0 0 10px rgb(0 0 0 / 0.3);
}

.menu-item {
  padding: 5px 10px;
  border-radius: 5px;
  background-color: #fff;
}

.menu-item:hover {
  background-color: #eee;
}
</style>
